/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.aaron.platform.dao;

import com.aaron.platform.exceptions.XmlParseException;
import com.aaron.platform.exceptions.XmlPathException;
import com.aaron.platform.entity.ItscPriExt;
import com.aaron.platform.entity.ItscPriInfo;

import com.aaron.platform.view.ItscTreeNode;
import java.io.File;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.apache.log4j.Logger;
import org.apache.myfaces.custom.tree2.TreeModel;
import org.apache.myfaces.custom.tree2.TreeModelBase;
import org.apache.myfaces.custom.tree2.TreeNode;
import org.apache.myfaces.custom.tree2.TreeNodeBase;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

/**
 * XML解析实现
 * @author mac
 */
public class XmlParserImp implements IXmlParser {

    private static Logger logger = Logger.getLogger(XmlParserImp.class);
    private final static String NODE_NAME_PRIVILEGE = "privilege";
    private final static String NODE_NAME_DISNAME = "disName";
    private final static String NODE_NAME_DESC = "desc";
    private final static String NODE_NAME_EXTENTIONS = "extentions";
    private final static String NODE_NAME_OPER = "oper";
    private final static String NODE_NAME_VALUE = "value";
    private final static String NODE_MENU_ROOT = "menu";
    private final static String NODE_MENU_ITEM = "menuItem";
    private final static String NODE_MENU_TYPE = "type";
    private final static String NODE_MENU_CHILD = "child";
    private final static String NODE_MENU_URL = "url";
    private final static String NODE_MENU_ROLES = "roles";

    public List<ItscPriInfo> parsePreInfoXml(File xmlFile) throws XmlPathException, XmlParseException {
        // 产生一个解析器
        SAXReader reader = new SAXReader();
        Document doc = null;
        try {
            // 读取文件
            doc = reader.read(xmlFile);

        } catch (DocumentException e) {
            logger.error("error to read a file:" + xmlFile.getAbsolutePath());
            throw new XmlPathException();
        }
        // 解析文档
        if (doc != null) {
            return parsePreInfoDoc(doc);
        }
        return null;
    }

    private List<ItscPriInfo> parsePreInfoDoc(Document document) throws XmlParseException {
        // 获取根节点
        Element root = document.getRootElement();
        List<ItscPriInfo> itscPreInfos = new ArrayList<ItscPriInfo>();
        for (Iterator elementIter = root.elementIterator(); elementIter.hasNext();) {
            Element privilegeElement = (Element) elementIter.next();

            // 节点名必须为“previlege”
            if (!privilegeElement.getName().equals(NODE_NAME_PRIVILEGE)) {
                logger.error("the node's name is invalid.");
                throw new XmlParseException();
            }

            // 获取name，如果为空则抛出异常
            String privilegeName = privilegeElement.attributeValue("name");
            if (null == privilegeName || privilegeName.equals("")) {
                logger.error("the name is null or empty.");
                throw new XmlParseException();
            }

            // 产生一个权限信息
            ItscPriInfo itscPreInfo = new ItscPriInfo(privilegeName);
            logger.debug("parse a privilege node, the name is " + privilegeName);

            // 设置显示属性
            Element disNameElement = privilegeElement.element(NODE_NAME_DISNAME);
            if (disNameElement == null || disNameElement.getTextTrim().equals("")) {
                logger.error("display name is null or empty.");
                throw new XmlParseException();
            }
            itscPreInfo.setPrivilegeDisname(disNameElement.getTextTrim());

            // 设置描述信息，描述信息允许为空
            Element descElement = privilegeElement.element(NODE_NAME_DESC);
            if (descElement != null) {
                itscPreInfo.setPrivilegeDesc(descElement.getTextTrim());
            }

            // 加入到列表中
            itscPreInfos.add(itscPreInfo);

            // 获取扩展属性,若无扩展属性，继续处理下一个节点
            Element extElement = privilegeElement.element(NODE_NAME_EXTENTIONS);
            if (extElement == null) {
                logger.debug("previlege(" + itscPreInfo.getPrivilegeName() + ") has no extentions.");
                continue;
            }

            // 获取扩展属性字节点
            for (Iterator subIter = extElement.elementIterator(); subIter.hasNext();) {
                Element extSubElement = (Element) subIter.next();
                if (!extSubElement.getName().equals(NODE_NAME_OPER)) {
                    logger.error("extention element doesn't have a oper name.");
                    throw new XmlParseException();
                }
                String extName = extSubElement.attributeValue("name");

                // 名字不允许为空
                if (extName == null || extName.equals("")) {
                    logger.error("extation's name is null.");
                    throw new XmlParseException();
                }

                // 创建一个扩展权限，设置属性
                logger.debug("parse a extention, the name is " + extName);
                ItscPriExt itscPriExt = new ItscPriExt(extName);

                // 设置显示名，必须有
                Element extOperDisElement = extSubElement.element(NODE_NAME_DISNAME);
                if (extOperDisElement == null || extOperDisElement.getTextTrim().equals("")) {
                    logger.error("the extation property's display name is null or empty.");
                    throw new XmlParseException();
                }
                itscPriExt.setOperDisname(extOperDisElement.getTextTrim());

                // 设置扩展属性值，必须有
                Element operElement = extSubElement.element(NODE_NAME_VALUE);
                if (operElement == null || operElement.getTextTrim().equals("")) {
                    logger.error("the extation property's value is null or empty.");
                    throw new XmlParseException();
                }
                itscPriExt.setOperValue(Integer.valueOf(operElement.getTextTrim()));

                // 加入到权限信息
                itscPreInfo.addPriExt(itscPriExt);
            }
        }
        return itscPreInfos;
    }

    public TreeModel parseMenuXml(File xmlFile, String roleName) throws XmlPathException, XmlParseException {
        // 产生一个解析器
        SAXReader reader = new SAXReader();
        Document doc = null;
        try {
            // 读取文件
            doc = reader.read(xmlFile);

        } catch (DocumentException e) {
            logger.error("error to read a file:" + xmlFile.getAbsolutePath());
            throw new XmlPathException();
        }
        // 解析文档
        if (doc != null) {
            return parseMenuDocModel(doc, roleName);
        }
        return null;
    }

    private TreeModel parseMenuDocModel(Document document, String roleName) throws XmlParseException {

        // 获取根节点
        Element root = document.getRootElement();
        if (root == null || root.getName() == null || !NODE_MENU_ROOT.equals(root.getName())) {
            logger.error("Failed to parse root node of menu xml file.");
            throw new XmlParseException();
        }
        TreeNode rootNode = new TreeNodeBase(root.attributeValue(NODE_MENU_TYPE),
                root.attributeValue(NODE_NAME_DISNAME),
                NODE_MENU_CHILD.equals(root.attributeValue(NODE_MENU_TYPE)) ? true : false);

        parseSubNode(root, rootNode, roleName);

        return new TreeModelBase(rootNode);
    }

    /**
     * 获取当前节点及子节点
     * @param element 当前xml节点
     * @param treeNode 当前树节点
     * @param roleName 角色名
     * @throws XmlParseException
     */
    private void parseSubNode(Element element, TreeNode treeNode, String roleName) throws XmlParseException {

        // 循环节点
        for (Iterator elementIter = element.elementIterator(); elementIter.hasNext();) {
            Element subElement = (Element) elementIter.next();
            
            if (subElement == null || subElement.getName() == null || !NODE_MENU_ITEM.equals(subElement.getName())) {
                logger.error("Failed to parse sub node of menu xml file.");
                throw new XmlParseException();
            }

            String roles = subElement.attributeValue(NODE_MENU_ROLES);
            if (!isRoleAllowed(roles, roleName)) {
                continue;
            }

            // 构造树节点
            ItscTreeNode subNodeBase = new ItscTreeNode(subElement.attributeValue(NODE_MENU_TYPE),
                subElement.attributeValue(NODE_NAME_DISNAME),
                NODE_MENU_CHILD.equals(subElement.attributeValue(NODE_MENU_TYPE)) ? true : false,
                NODE_MENU_CHILD.equals(subElement.attributeValue(NODE_MENU_TYPE)) ? subElement.attributeValue(NODE_MENU_URL) : null);
            
            // 设置是否可显示
            subNodeBase.setRendered(roleName);
            
            parseSubNode(subElement, subNodeBase, roleName);

            treeNode.getChildren().add(subNodeBase);
        }
    }

    /**
     * 节点是否授权给角色
     * @param roles 允许的角色集合
     * @param roleName 角色名
     * @return 是否授权
     */
    private boolean isRoleAllowed(String roles, String roleName) {
        String roleArray[] = roles.split(",");
        for (String roleNameS : roleArray) {
            if (roleNameS.equals(roleName)) {
                return true;
            }
        }
        return false;
    }
}
